<?php

namespace mForge\Modules\Cache;

/**
 * File cache handler.
  */
class FileCacheHandler implements ICacheHandler
{
    /**
     * The path to the directory where to store the cache files.
     *
     * @var string
     */
    private $cacheDir;
    
    /**
     * The life time of the cache (in seconds).
     * 
     * @var integer
     */
    private $lifeTime;

    /**
     *
     * @param \mForge\Application $app
     * @param array $options
     * @return FileCacheHandler
     */
    public function __construct(\mForge\Application $app, array $options)
    {
        $defaults = array(
            'cacheDir' => 'cache',
            'lifeTime' => 3600
        );

        $options = \mForge\Utility::arrayOverlay($defaults, $options);

        $cacheDir = $app->getAppPath() . DIRECTORY_SEPARATOR 
                  . trim($options['cacheDir'], DIRECTORY_SEPARATOR)
                  . DIRECTORY_SEPARATOR;

        if (!is_dir($cacheDir)) {
            throw new \Exception($cacheDir . ' is not a directory.');
        } else if (!is_writable($cacheDir)) {
            throw new \Exception($cacheDir . 'is not writable.');
        }

        $this->cacheDir = $cacheDir;
        $this->lifeTime = (int)$options['lifeTime'];

        return $this;
    }

    /**
     * Clean the cache.
     *
     * @param string $id
     */
    public function clean($id)
    {
        $cacheFile = $this->cacheDir . $id;
        if (is_file($cacheFile)) {
            unlink($cacheFile);
        }
        return $this;
    }

    /**
     *
     * @return FileCacheHandler 
     */
    public function cleanAll()
    {
        $dir = new \DirectoryIterator($this->cacheDir);
        foreach ($dir as $file) {
            if ($dir->isFile()) {
                unlink($file->getPathname());
            }
        }
        return $this;
    }

    /**
     * Load cache from disk.
     *
     * @param string $id
     * @return mixed
     */
    public function load($id)
    {
        $file = $this->cacheDir . $id;
        if (!is_file($file)) {
            return null;   
        }
        
        $contents = file_get_contents($file);
        if (!$contents) {
            return null;
        }
        
        $fileData = explode("\n", $contents, 2);
        if (count($fileData) != 2) {
            return null;
        }
        
        // Check if the cache is expired
        if (time() >= $fileData[0]) {
            return null;
        }
        
        $value = unserialize($fileData[1]);
        if ($value === false) {
            return null;
        }
        return $value;
    }

    /**
     * Save the cache and metadata to disk.
     *
     * @param string $id
     * @param string $data
     * @return FileCacheHandler
     */
    public function save($id, $data, $lifeTime = null)
    {
        if ($lifeTime === null) {
            $lifeTime = $this->lifeTime;
        }

        file_put_contents($this->cacheDir . $id, time() + $lifeTime . "\n" . serialize($data));

        return $this;
    }
}